package com.gz.EuchreU.Sprite;

import org.anddev.andengine.entity.modifier.MoveModifier;
import org.anddev.andengine.entity.modifier.ParallelEntityModifier;
import org.anddev.andengine.entity.modifier.RotationModifier;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.util.modifier.ease.EaseStrongOut;

import android.util.Log;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.gz.EuchreU.Contants.CardLocations;
import com.gz.EuchreU.Contants.CardValues;
import com.gz.EuchreU.Contants.GameOptions;
import com.gz.EuchreU.Contants.GameState;
import com.gz.EuchreU.Contants.Scenes;
import com.gz.EuchreU.Contants.Suits;
import com.gz.EuchreU.Contants.UI;
import com.gz.EuchreU.Helpers.HelperMethods;

public class Card extends AnimatedSprite {

	public static final int STATE_INIT = 0;
	public static final int STATE_MOVE_SHUFFLE = STATE_INIT + 1;
	public static final int STATE_DEALING = STATE_MOVE_SHUFFLE + 1;
	public static final int STATE_MOVE_DEALT = STATE_DEALING + 1;
	public static final int STATE_IN_HAND = STATE_MOVE_DEALT + 1;
	public static final int STATE_MOVE_PLAY = STATE_IN_HAND + 1;
	public static final int STATE_IN_PLAY = STATE_MOVE_PLAY + 1;
	public static final int STATE_DISCARDED = STATE_IN_PLAY + 1;
	public static final int STATE_TURNCARD = STATE_DISCARDED + 1;

	// private static final int MAX_SPEED = 20;

	private int mCardID = 99999;
	private int mSuitID, mValueID;
	private Vector2 mLocalTouch = new Vector2();
	// private MoveModifier mMover;
	private ParallelEntityModifier mShapeMod;
	// private Body mBody;

	// Variables that Reset
	private int mCardState = STATE_INIT;
	private Vector2 mMoveToLocation = new Vector2();
	private int mOwner = -1;
	private int mHandPosition = -1;
	private boolean mDisabled = false;
	private boolean mTouched = false;

	public Card(float pX, float pY, int pSuitID, int pValueID) {
		super(pX, pY, UI.getCardWidth(), UI.getTextures()
				.getHeightFromWidthTiled(pSuitID, pValueID, UI.getCardWidth()),
				UI.getTextures().getCardTiledTextureRegion(pSuitID, pValueID));
		Init(pSuitID, pValueID);
	}

	public Card(float pX, float pY, float pWidth, int pSuitID, int pValueID) {
		super(pX, pY, pWidth, UI.getTextures().getHeightFromWidthTiled(pSuitID,
				pValueID, pWidth), UI.getTextures().getCardTiledTextureRegion(
				pSuitID, pValueID));
		Init(pSuitID, pValueID);
	}

	private void Init(int pSuitID, int pValueID) {
		Hide();

		mCardID = CardValues.getNewCardID();
		mSuitID = pSuitID;
		mValueID = pValueID;
	}

	public int GetSuitID() {
		return mSuitID;
	}

	public int GetValueID() {
		return mValueID;
	}

	@Override
	protected void onManagedUpdate(final float pSecondsElapsed) {
		// this.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX,
		// pTouchAreaLocalY)
		switch (mCardState) {
		case STATE_DEALING:
			Hide();
			break;
		case STATE_DISCARDED:
			Hide();
			break;
		case STATE_IN_HAND:
			if (GameState.IsHuman(mOwner)) {
				Show();
				if (mTouched && IsCurrentCard()) {
					CheckPlayable();
				}
			} else
				Hide();
			break;
		case STATE_IN_PLAY:
			Show();
			break;
		case STATE_MOVE_DEALT:
		case STATE_MOVE_PLAY:
		case STATE_MOVE_SHUFFLE:
			if (mShapeMod != null) {
				if (mShapeMod.isFinished()) {
					if (mCardState == STATE_MOVE_DEALT)
						mCardState = STATE_IN_HAND;
					else if (mCardState == STATE_MOVE_SHUFFLE)
						mCardState = STATE_DEALING;
					else if (mCardState == STATE_MOVE_PLAY)
						mCardState = STATE_IN_PLAY;
				}
			} else
				Log.w("Playing Card", "Mover is null..");

			break;
		case STATE_TURNCARD:
			Show();
			break;
		default:
			Hide();
			break;
		}
		super.onManagedUpdate(pSecondsElapsed);
	}

	@Override
	public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
			float pTouchAreaLocalX, float pTouchAreaLocalY) {
		switch (pSceneTouchEvent.getAction()) {
		case TouchEvent.ACTION_DOWN:
			if (GameState.IsHuman(mOwner)) {
				CardValues.setCurrentCard(mCardID);
				mLocalTouch = new Vector2(pSceneTouchEvent.getX() - getX(),
						pSceneTouchEvent.getY() - getY());
				SelectCard(true);
				// BringToFront();
			}

			return true;
		case TouchEvent.ACTION_UP:
			if (IsCurrentCard()) {
				CardValues.setCurrentCard(-1);
				mLocalTouch = new Vector2();
				SelectCard(false);
				if (IsOnPlayedPosition()) {
					GameState.GetPlayers()[mOwner].HumanPlayCard(Card.this);
				} else {
					MoveBackToHand();
				}
				return true;
			} else
				return false;
		case TouchEvent.ACTION_MOVE:
			if (IsCurrentCard()) {
				return onCardTouched(pSceneTouchEvent);
			} else
				return false;
		default:
			return false;
		}
	}

	public boolean onCardTouched(TouchEvent pSceneTouchEvent) {
		switch (pSceneTouchEvent.getAction()) {
		case TouchEvent.ACTION_UP:
			if (IsCurrentCard()) {
				CardValues.setCurrentCard(-1);
				mLocalTouch = new Vector2();
				SelectCard(false);

				if (IsOnPlayedPosition()) {
					GameState.GetPlayers()[mOwner].HumanPlayCard(Card.this);
				} else {
					MoveBackToHand();
				}

				return true;
			} else
				return false;
		case TouchEvent.ACTION_MOVE:
			if (IsCurrentCard()) {
				CheckPlayable();
				setPosition(pSceneTouchEvent.getX() - mLocalTouch.x,
						pSceneTouchEvent.getY() - mLocalTouch.y);
			}
			return true;
		default:
			return false;
		}
	}

	public void setDisabled(boolean blnDisabled) {
		mDisabled = blnDisabled;
		if (!blnDisabled) {
			setColor(1f, 1f, 1f);
			setAlpha(1f);
		} else {
			setColor(.5f, .5f, .5f);
			setAlpha(.25f);
		}
	}

	public boolean getDisabled() {
		return mDisabled;
	}

	private boolean CheckPlayable() {
		if (IsOnPlayedPosition()) {
			setColor(0, 1, .5f);
			return true;
		} else if (IsPlayable()) {
			setColor(0, .75f, .75f);
			return false;
		} else {
			setColor(.75f, .15f, .05f);
			return false;
		}
	}

	public boolean IsOnPlayedPosition() {
		Vector2 playLoc = CardLocations.GetTrickCardLocation(mOwner);
		if (GameState.getCurrentPlayer() != mOwner) {
			return false;
		} else if (getX() - playLoc.x < getWidth()
				&& getX() - playLoc.x > -getWidth()
				&& getY() - playLoc.y < getHeight()
				&& getY() - playLoc.y > -getHeight()) {
			return IsPlayable();
		} else
			return false;
	}

	private boolean IsPlayable() {
		return GameState.GetPlayers()[mOwner].CanPlayCard(this);
	}

	public void setBody(Body pBody) {
		// mBody = pBody;
	}

	public int getCardID() {
		return mCardID;
	}

	public boolean IsSameSuitAsLead() {
		if (GameState.GetCurrentTrickCount() == 0) {
			return true;
		} else {
			if (IsLeft()) {
				return GameState.GetLeadCard().IsTrump();
			} else {
				if (GameState.GetLeadCard().IsLeft()) {
					return IsTrump();
				} else
					return GetSuitID() == GameState.GetLeadCard().GetSuitID();
			}
		}
	}

	public boolean IsSuit(int pSuitID) {
		if (IsLeft()) {
			return pSuitID == Suits.getTrumpID();
		} else
			return pSuitID == GetSuitID();
	}

	private boolean IsJack() {
		return GetValueID() == CardValues.JACK;
	}

	public boolean IsTrump() {
		if (IsLeft())
			return true;
		else
			return GetSuitID() == Suits.getTrumpID();
	}

	public boolean IsRight() {
		return GetSuitID() == Suits.getTrumpID() && IsJack();
	}

	public boolean IsLeft() {
		return GetSuitID() == Suits.getLeftSuitID() && IsJack();
	}

	public int GetCardHandValue() {

		if (IsRight()) {
			return VALUES_RIGHT_BAUER;
		} else if (IsLeft()) {
			return VALUES_LEFT_BAUER;
		} else if (IsTrump()) {
			return VALUES_TRUMP_BONUS + GetValueID();
		} else if (IsSameSuitAsLead()) {
			return VALUES_FOLLOW_BONUS + GetValueID();
		} else
			return GetValueID();
	}

	public static final int VALUES_RIGHT_BAUER = 40;
	public static final int VALUES_LEFT_BAUER = 35;
	public static final int VALUES_TRUMP_BONUS = 20;
	public static final int VALUES_FOLLOW_BONUS = 10;

	public int GetPotentialCardValue(int pSuitID) {
		if (IsPotentialRight(pSuitID)) {
			return VALUES_RIGHT_BAUER;
		} else if (IsPotentialLeft(pSuitID)) {
			return VALUES_LEFT_BAUER;
		} else if (IsPotentialTrump(pSuitID)) {
			return VALUES_TRUMP_BONUS + GetCardBaseValue();
		} else
			return GetCardBaseValue() * 2;
	}

	public int GetCardBaseValue() {
		if (GetValueID() == CardValues.ACE) {
			return GetValueID() * 2;
		} else if (GetValueID() == CardValues.KING
				|| GetValueID() == CardValues.QUEEN) {
			return (int) (GetValueID() * 1.5f);
		} else
			return GetValueID();
	}

	public int[] GetPotentialCardValues() {
		int[] intReturn = new int[4];
		for (int i = 0; i < intReturn.length; i++) {
			intReturn[i] = GetPotentialCardValue(i);
		}
		return intReturn;
	}

	private boolean IsPotentialTrump(int pTrumpID) {
		if (IsPotentialLeft(pTrumpID))
			return true;
		else
			return mSuitID == pTrumpID;
	}

	private boolean IsPotentialRight(int pTrumpID) {
		return mSuitID == pTrumpID && mValueID == CardValues.JACK;
	}

	private boolean IsPotentialLeft(int pTrumpID) {
		return mSuitID == Suits.getPotentialLeftSuitID(pTrumpID)
				&& mValueID == CardValues.JACK;
	}

	public boolean IsCurrentCard() {
		return CardValues.getCurrentCard() == mCardID;
	}

	public boolean IsMoving() {
		switch (mCardState) {
		case STATE_MOVE_DEALT:
		case STATE_MOVE_PLAY:
		case STATE_MOVE_SHUFFLE:
			return true;
		default:
			return false;
		}
	}

	public void setOwner(int pPlayerID) {
		mOwner = pPlayerID;
	}

	public void setState(int pCardState) {
		mCardState = pCardState;
	}

	public void Reset() {
		mCardState = STATE_INIT;
		mOwner = -1;
		mHandPosition = -1;
		setRotation(0);
	}

	private void Hide() {
		if (GameOptions.GetBoolOption(GameOptions.PREF_BOOL_SHOW_AI)) {
			if (getCurrentTileIndex() != 0) {
				setCurrentTileIndex(0);
			}
		} else if (getCurrentTileIndex() != 1) {
			setCurrentTileIndex(1);
		}
	}

	private void Show() {
		if (getCurrentTileIndex() != 0) {
			setCurrentTileIndex(0);
		}
	}

	public void BringToFront() {
		// setZIndex(CardValues.getNextZ());

		UI.GetGame().runOnUpdateThread(new Runnable() {

			public void run() {
				Scenes.getEuchreGameScene().unregisterTouchArea(Card.this);
				Scenes.getEuchreGameScene().getChild(CardValues.LAYER_CARDS)
						.detachChild(Card.this);
				Scenes.getEuchreGameScene().registerTouchArea(Card.this);
				Scenes.getEuchreGameScene().getChild(CardValues.LAYER_CARDS)
						.attachChild(Card.this);
			}
		});
	}

	public void SelectCard(boolean blnSelected) {
		if (blnSelected) {
			setColor(0, .75f, .75f);
		} else {
			setColor(1, 1f, 1f);
			if (IsCurrentCard())
				CardValues.ResetCurrentCard();
		}

		mTouched = blnSelected;
	}

	public void MoveToShuffle(Vector2 pMoveToLocation) {
		Hide();
		mCardState = STATE_MOVE_SHUFFLE;
		MoveTo(pMoveToLocation);
		// log("MoveToShuffle: " + pMoveToLocation.x + "," + pMoveToLocation.y);
	}

	private void MoveBackToHand() {
		MoveToHand(mOwner, mHandPosition, false);
	}

	public void MoveToHand(int pPlayerID, int pPosition, boolean pBringToFront) {
		mHandPosition = pPosition;
		boolean blnIsSide = (pPlayerID == GameState.PLAYER_EAST || pPlayerID == GameState.PLAYER_WEST);
		mCardState = STATE_MOVE_DEALT;
		mOwner = pPlayerID;
		mMoveToLocation = CardLocations.GetPlayerCardLocation(pPlayerID);
		if (blnIsSide) {
			mMoveToLocation.y += pPosition * getWidth() / 2;
		} else {
			mMoveToLocation.x += pPosition * getWidth() / 2;
		}

		log("MoveToHand: " + pPlayerID + ":" + pPosition + " - "
				+ mMoveToLocation.x + "," + mMoveToLocation.y);
		if (GameState.IsHuman(pPlayerID))
			Show();
		MoveTo(mMoveToLocation, pBringToFront, blnIsSide);

	}

	public void MoveToPlay() {
		mCardState = STATE_MOVE_PLAY;

		setColor(.9f, .9f, .9f);
		mMoveToLocation = CardLocations.GetTrickCardLocation(mOwner);
		if (GameState.IsHuman(mOwner)) {
			setPosition(mMoveToLocation.x, mMoveToLocation.y);
		} else {
			MoveTo(CardLocations.GetTrickCardLocation(mOwner));
		}

		Show();
		// log("MoveToPlay: " + pMoveToLocation.x + "," + pMoveToLocation.y);

	}

	public void MoveToDiscard() {
		mCardState = STATE_DISCARDED;
		SelectCard(false);
		MoveTo(new Vector2(-2 * UI.getCardWidth(), 0), false, false);
	}

	public void MoveTo(Vector2 pMoveToLocation, boolean pMoveToFront,
			boolean pRotated) {
		if (pMoveToFront) {
			BringToFront();
		}
		mMoveToLocation = pMoveToLocation;

		float duration = getMoveDuration();
		float rotation = 180;
		if (GetDistanceToMoveTo() > 150)
			rotation += 180;
		if (pRotated) {
			if (GetDistanceToMoveTo() > 150)
				rotation += 90;
			else
				rotation -= 90;
		}
		mShapeMod = new ParallelEntityModifier(new MoveModifier(duration,
				getX(), mMoveToLocation.x, getY(), mMoveToLocation.y,
				EaseStrongOut.getInstance()), new RotationModifier(duration, 0,
				rotation, EaseStrongOut.getInstance()));

		log("MoveTo: " + pMoveToLocation.x + "," + pMoveToLocation.y);

		
		
		clearEntityModifiers();
		this.registerEntityModifier(mShapeMod);

	}

	private float getMoveDuration() {
		switch (GameOptions.GetIntOption(GameOptions.PREF_INT_GAME_SPEED)) {
		case 0:
			return 3;
		case 1:
			return 2.25f;
		case 2:
			return 1.75f;
		case 3:
			return 1.25f;
		default:
			return .75f;
		}
	}

	public void MoveTo(Vector2 pMoveToLocation) {
		MoveTo(pMoveToLocation, true, false);
	}

	public double GetDistanceToMoveTo() {
		return GetDistanceToPoint(mMoveToLocation);
	}

	public double GetDistanceToPoint(Vector2 pPoint) {
		return HelperMethods.getDistanceFromPointToPoint(new Vector2(getX(),
				getY()), pPoint);
	}

	private void log(String msg) {
		Log.d("Card:" + mCardState + "-" + ToString(), msg);
	}

	public String ToString() {
		return CardValues.ToString(mValueID) + " of " + Suits.ToString(mSuitID);
	}

	public String ToShortString() {
		String val = CardValues.ToString(mValueID);
		String suit = Suits.ToString(mSuitID);

		return val.substring(0, 1).toUpperCase() + ""
				+ suit.substring(0, 1).toUpperCase();
	}
}
